package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.enums.DWaybillStatusEnum;
import cn.huiyunche.base.service.enums.DWaybillStatusTypeEnum;
import cn.huiyunche.base.service.enums.TmsOrderOperationStatusEnum;
import cn.huiyunche.base.service.enums.TmsUserTypeEnum;
import cn.huiyunche.base.service.framework.utils.TmsQueueApi;
import cn.huiyunche.base.service.interfaces.DUserAddressService;
import cn.huiyunche.base.service.interfaces.DWaybillService;
import cn.huiyunche.base.service.interfaces.DWaybillStatusHistoryService;
import cn.huiyunche.base.service.interfaces.TmsQueueService;
import cn.huiyunche.base.service.mappers.*;
import cn.huiyunche.base.service.mappers.ext.SUserViewMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.utils.DateUtils;
import cn.huiyunche.base.service.vo.*;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 中联派单队列服务实现
 *
 * @author hdy [Tuffy]
 */

@Service
public class TmsQueueServiceImpl implements TmsQueueService {

    private static final Logger LOGGER = LoggerFactory.getLogger(TmsQueueServiceImpl.class);

    @Autowired
    private DUserMapper dUserMapper = null;

    @Autowired
    private DUserExtMapper dUserExtMapper = null;

    @Autowired
    private DUserLicenseMapper dUserLicenseMapper = null;

    @Autowired
    private CDriverCertinfoMapper cDriverCertinfoMapper = null;

    @Autowired
    private DWaybillMapper dWaybillMapper = null;

    @Autowired
    private DUserAddressService dUserAddressService = null;

    @Autowired
    private DWaybillService dWaybillService = null;

    @Autowired
    private DWaybillStatusHistoryService dWaybillStatusHistoryService = null;

    @Autowired
    private SUserViewMapper sUserViewMapper;

    @Override
    public void start() throws Exception {
        // 检查是否为首次调度或者订单队列执行完毕
        if (!TmsQueueApi.isRootStartQueue()) {
            LOGGER.info("================队列没有收到开始派单指令===============");
            return;
        }
        if (TmsQueueApi.isStartQueue()) {
            LOGGER.info("================队列正在进行===============");
            return;
        }
        // 首次调度或者订单队列执行完毕
        TmsQueueApi.setStartQueue(true);
        LOGGER.info("================队列开始进行===============");
        this.dispatch(false);
    }

    @Override
    public void appendOrder(TmsQueueOrderVo eov) throws Exception {
        if (null != eov) {
            TmsQueueApi.removeOrder(eov.getWaybillId(), eov.getTmsSerialNo());
            TmsQueueApi.appendOrder(eov);
        }
    }

    @Override
    public void lPushOrder(TmsQueueOrderVo eov) throws Exception {
        if (null != eov) {
            TmsQueueApi.removeOrder(eov.getWaybillId(), eov.getTmsSerialNo());
            TmsQueueApi.appendOrder4First(eov);
        }

    }

    @Override
    public void removeOrder(String waybillId, String tmsSerialNo) throws Exception {
        TmsQueueApi.removeOrder(waybillId, tmsSerialNo);
    }

    @Override
    public void appendDriver(String phone) throws Exception {
        TmsQueueDriverVo isExitDriver = TmsQueueApi.getNextDriver(phone);
        if (null != isExitDriver) {
            TmsQueueApi.removeDriver(phone);
        }
        TmsQueueDriverVo tqdv = new TmsQueueDriverVo();
        tqdv.setDateTime(new Date().getTime());
        tqdv.setPhone(phone);
        // 设置常跑路线
        //tqdv.setLines(this.getLines(phone));
        // tms用户
        if (this.appendDriver4Tms(tqdv)) {
            TmsQueueApi.appendDriver(tqdv);
            return;
        }
        // 平台注册用户，加入队列
        this.appendDriver4Platform(tqdv);
        TmsQueueApi.appendDriver(tqdv);
    }

    @Override
    public void removeDriver(String phone) throws Exception {
        TmsQueueApi.removeDriver(phone);
    }

    @Override
    public TmsQueueDriverRtnVo getMyself(String phone) {
        return TmsQueueApi.getNextDriver(phone);
    }

    @Override
    public Result<String> resetQueueOrder(String orderCodes) throws Exception {
        Result<String> r = new Result<>(true);
        if (StringUtils.isBlank(orderCodes)) {
            r.setSuccess(false);
            r.setMessage("订单号不可为空");
            return r;
        }
        List<String> dwaybillOrderCodeIds = this.getOrderCodeList(orderCodes);
        if (dwaybillOrderCodeIds.size() <= 0) {
            r.setSuccess(false);
            r.setMessage("订单数据不存在");
            return r;
        }
        DWaybillExample dwe = new DWaybillExample();
        dwe.createCriteria().andUserIdEqualTo(0L).andOrderCodeIn(dwaybillOrderCodeIds);
        List<DWaybill> dWaybillList = this.dWaybillMapper.selectByExample(dwe);
        int size = dWaybillList.size();
        StringBuffer sb = new StringBuffer("");
        if (size > 0) {
            sb.append("置顶").append(size).append("个订单。");
            for (int i = size - 1; i >= 0; i--) {
                DWaybill dw = dWaybillList.get(i);
                TmsQueueOrderVo vo = new TmsQueueOrderVo();
                vo.setWaybillId(dw.getId().toString());
                vo.setTmsSerialNo(dw.getOrderLineId().toString());
                vo.setFrom(dw.getDepartureCity());
                vo.setTo(dw.getDestCity());
                vo.setUrgent(dw.getIsUrgent());
                sb.append(dw.getOrderCode()).append(",");
                TmsQueueApi.removeOrder(vo.getWaybillId(), vo.getTmsSerialNo());
                TmsQueueApi.appendOrder4First(vo);
            }
        } else {
            sb.append("没有指定订单数据");
        }
        String sbStr = sb.toString();
        r.setData(sbStr.endsWith(",") ? sbStr.substring(0, sbStr.length() - 1) : sbStr);
        r.setMessage("重置缓存订单顺序成功");
        return r;
    }

    @Override
    public Result<List<DWaybill>> queueOrderList() throws Exception {
        Result<List<DWaybill>> r = new Result<>(true);
        List<TmsQueueOrderVo> list = TmsQueueApi.orderList();
        List<Long> dwaybillIds = new ArrayList<>();
        for (TmsQueueOrderVo tqov : list) {
            dwaybillIds.add(NumberUtils.toLong(tqov.getWaybillId()));
        }
        if (dwaybillIds.size() > 0) {
            DWaybillExample dwe = new DWaybillExample();
            dwe.createCriteria().andIdIn(dwaybillIds);
            r.setData(this.dWaybillMapper.selectByExample(dwe));
        }
        return r;
    }

    @Override
    public Result<List<DUserExt>> queueDriverList() throws Exception {
        Result<List<DUserExt>> result = new Result<>(true, null, "数据加载成功");
        List<TmsQueueDriverVo> driverVos = TmsQueueApi.driverList();
        LOGGER.info("queueDriverList: {}", JSONArray.toJSONString(driverVos));
        List<DUserExt> dUserExts = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(driverVos)) {
            List<String> phones = driverVos.stream().map(value -> value.getPhone()).collect(Collectors.toList());
            LOGGER.info("phones: {}", JSONArray.toJSONString(phones));
            if (null != phones && phones.size() > 0) {
                DUserExtExample example = new DUserExtExample();
                example.createCriteria().andPhoneIn(phones);
                dUserExts = this.dUserExtMapper.selectByExample(example);
            }
        }
        result.setData(dUserExts);
        return result;
    }

    @Override
    public Result<String> removeQueueOrder(String orderCodes) throws Exception {
        Result<String> r = new Result<>(true);
        if (StringUtils.isBlank(orderCodes)) {
            r.setSuccess(false);
            r.setMessage("订单号不可为空");
            return r;
        }
        List<String> dwaybillOrderCodeIds = this.getOrderCodeList(orderCodes);
        DWaybillExample dwe = new DWaybillExample();
        dwe.createCriteria().andOrderCodeIn(dwaybillOrderCodeIds);
        List<DWaybill> dWaybillList = this.dWaybillMapper.selectByExample(dwe);
        for (DWaybill dw : dWaybillList) {
            Long waybillId = dw.getId();
            // 修改订单状态
            dw.setWaybillStatus(DWaybillStatusEnum.CANCEL.getValue());
            dw.setOperationStatus(TmsOrderOperationStatusEnum.CANCEL.getValue());
            this.dWaybillMapper.updateByPrimaryKeySelective(dw);
            // 添加日志
            this.dWaybillStatusHistoryService.add(waybillId, DWaybillStatusTypeEnum.OPERATION.getText(), TmsOrderOperationStatusEnum.CANCEL.getText(),
                    DWaybillStatusEnum.getByValue(dw.getWaybillStatus()).getText(), 0L, "后台取消");
            // 删除缓存
            removeOrder(waybillId.toString(), dw.getOrderLineId().toString());
        }
        r.setSuccess(true);
        return r;
    }

    /**
     * 添加tms司机到队列
     *
     * @param tqdv 司机队列对象
     */
    @Override
    public boolean appendDriver4Tms(TmsQueueDriverVo tqdv) throws Exception {
        String phone = tqdv.getPhone();
        // 获取tms用户，没有说明是平台注册用户
        DUserExample due = new DUserExample();
        due.createCriteria().andLoginNameEqualTo(phone).andEnableEqualTo(true).andTypeEqualTo(TmsUserTypeEnum.DRIVER.getValue());
        List<DUser> duList = this.dUserMapper.selectByExample(due);
        DUser du = duList.size() > 0 ? duList.get(0) : null;
        if (null == du) {
            return false;
        }
        // 驾照信息
        DUserLicenseExample dule = new DUserLicenseExample();
        dule.createCriteria().andUserIdEqualTo(du.getId());
        List<DUserLicense> dulList = this.dUserLicenseMapper.selectByExample(dule);
        StringBuffer sb = new StringBuffer("");
        for (DUserLicense dul : dulList) {
            sb.append(dul.getLicenseName()).append(",");
        }
        String licenseStr = sb.toString();
        if (licenseStr.endsWith(",")) {
            licenseStr = licenseStr.substring(0, licenseStr.length() - 1);
        }
        tqdv.setLicense(licenseStr);
        return true;
    }

    /**
     * 获取订单编号
     *
     * @param orderCodes 订单编号
     * @return 结果集
     */
    private List<String> getOrderCodeList(String orderCodes) throws Exception {
        List<String> list = new ArrayList<>();
        if (StringUtils.isNotBlank(orderCodes)) {
            orderCodes = orderCodes.replaceAll("，", ",");
            String[] orderCodesArray = orderCodes.split(",");
            for (String s : orderCodesArray) {
                list.add(s.trim());
            }
        }
        return list;
    }

    /**
     * 添加平台注册司机到队列
     *
     * @param tqdv 司机对象
     */
    @Override
    public void appendDriver4Platform(TmsQueueDriverVo tqdv) throws Exception {
        String phone = tqdv.getPhone();
        SUser su = this.dUserAddressService.getUser(phone);
        if (null == su) {
            return;
        }
        CDriverCertinfoExample cdce = new CDriverCertinfoExample();
        cdce.createCriteria().andUserIdEqualTo(su.getId());
        List<CDriverCertinfo> list = this.cDriverCertinfoMapper.selectByExample(cdce);
        CDriverCertinfo cdc = list.size() > 0 ? list.get(0) : null;
        if (null == cdc) {
            return;
        }
        // TODO 证件信息暂未开发，默认暂定为B1
        tqdv.setLicense("B1");
    }

    /**
     * 获取司机常跑路线列表
     *
     * @param phone 手机号
     * @return 结果集
     */
    private List<TmsQueueDriverLineVo> getLines(String phone) throws Exception {
        List<DUserAddress> list = this.dUserAddressService.getList(phone);
        if (null != list) {
            List<TmsQueueDriverLineVo> tList = new ArrayList<>();
            for (DUserAddress dua : list) {
                TmsQueueDriverLineVo tqdlv = new TmsQueueDriverLineVo();
                tqdlv.setFrom(dua.getDepartProvinceName());
                tqdlv.setTo(dua.getReceiptProvinceName());
                tList.add(tqdlv);
            }
            return tList;
        }
        return null;
    }

    /**
     * 派单
     *
     * @param isSecond 是否为二次匹配
     */
    private void dispatch(boolean isSecond) throws Exception {
        try {
            // 获取首个订单
            LOGGER.info("================队列获取订单======开始=========");
            TmsQueueOrderVo tqev = TmsQueueApi.getNextOrder();
            LOGGER.info("================队列获取订单======结束=========");
            // 订单分配完毕，等待下次调度
            if (null == tqev) {
                LOGGER.info("================队列已经没有订单=============");
                TmsQueueApi.setStartQueue(false);
                return;
            }
            // 获取匹配司机
            LOGGER.info("================队列获取司机=====开始========");
            TmsQueueDriverVo tqdv = this.mateDriver(tqev, true, isSecond);
            LOGGER.info("================队列获取司机=====结束========");
            // 没有匹配，二次匹配
            if (null == tqdv) {
                // this.dispatch(true);
                LOGGER.info("================队列已经没有司机=============");
                TmsQueueApi.setStartQueue(false);
                return;
            } else {
                // 匹配成功，下单
                this.order(tqev, tqdv);
            }
        } catch (Exception e) {
            TmsQueueApi.setStartQueue(false);
        }
    }

    /**
     * 下单
     *
     * @param tqev 订单对象
     * @param tqdv 司机对象
     */
    private void order(TmsQueueOrderVo tqev, TmsQueueDriverVo tqdv) throws Exception {
        LOGGER.info("================队列开始派单=============");
        try {

            DWaybill waybill = dWaybillService.getByPrimaryId(Long.parseLong(tqev.getWaybillId()));
            // 派单
            dWaybillService.dispatchDWaybill(waybill, tqdv.getPhone(), false);
            LOGGER.info("================队列结束派单=============");

            LOGGER.info("================队列结束派单====移除队列数据=========");
            // 移除队列订单
            TmsQueueApi.removeOrder(tqev);
            // 移除队列司机
            TmsQueueApi.removeDriver(tqdv);
        } finally {
            // 继续派单
            LOGGER.info("================队列结束派单====二次派单=========");
            this.dispatch(false);
        }
    }

    /**
     * 匹配司机
     *
     * @param eov           订单对象
     * @param isFirstDriver 首次查找司机
     * @param isSecond      二次匹配
     * @return 司机对象
     */
    private TmsQueueDriverVo mateDriver(TmsQueueOrderVo eov, boolean isFirstDriver, boolean isSecond) throws Exception {
        // 获取司机队列信息
        TmsQueueDriverVo tqdv = TmsQueueApi.getNextDriver(isFirstDriver);
        // 最后一个司机已经匹配，但是还没有匹配上，则直接返回null
        if (null == tqdv) {
            return null;
        }
        // 准驾车型匹配成功
        if (this.mateLicense(eov.getLicenses(), tqdv.getLicense())) {
            // 二次匹配只匹配准驾车型
            if (isSecond) {
                return tqdv;
            }
            // 选择最优路线
            if (this.mateTmsLines(tqdv, eov)) {
                return tqdv;
            }
            // 继续匹配
            return this.mateDriver(eov, false, isSecond);
        }
        // 准驾车型匹配失败，继续匹配
        return this.mateDriver(eov, false, isSecond);
    }

    /**
     * 匹配准驾车型
     *
     * @param licenses 准驾列表
     * @param license  司机驾照
     * @return 是否匹配
     */
    private boolean mateLicense(List<String> licenses, String license) throws Exception {
        /*license = license == null ? "" : license;
		boolean isMate = false;
		for (String s: licenses) {
			if (license.contains(s)) {
				isMate = true;
				break;
			}
		}
		return isMate;*/
        return true;
    }

    /**
     * 匹配常跑路线
     *
     * @param lines 常跑路线
     * @param from  订单起运地
     * @param to    订单目的地
     * @return
     */
    @SuppressWarnings("unused")
    @Deprecated
    private boolean mateLines(List<TmsQueueDriverLineVo> lines, String from, String to) throws Exception {
		/*// 没有，即全国配送
		if (null == lines || lines.size() == 0) {
			return true;
		}
		// 订单路线 开始
		String orderFromStr = from.replaceAll("省", "");
		orderFromStr = orderFromStr.replaceAll("市", "");
		orderFromStr = orderFromStr.trim();
		
		// 订单路线 开始
		String orderToStr = to.replaceAll("省", "");
		orderToStr = orderToStr.replaceAll("市", "");
		orderToStr = orderToStr.trim();
		for (TmsQueueDriverLineVo tqdlv : lines) {
			// 常跑路线 开始
			String lineFromStr  = tqdlv.getFrom().replaceAll("省", "");
			lineFromStr = lineFromStr.replaceAll("市", "");
			lineFromStr = lineFromStr.trim();
			
			// 常跑路线 结束
			String lineToStr  = tqdlv.getTo().replaceAll("省", "");
			lineToStr = lineToStr.replaceAll("市", "");
			lineToStr = lineToStr.trim();
			// 匹配
			if (lineFromStr.equals(orderFromStr) && lineToStr.equals(orderToStr)) {
				return true;
			}
		}
		return false;*/
        return true;
    }

    /**
     * 获取最优路线
     *
     * @param tqdv 司机对象
     * @param eov  订单对象
     * @return 是否匹配成功
     */
    private boolean mateTmsLines(TmsQueueDriverVo tqdv, TmsQueueOrderVo eov) throws Exception {

        return true;
    }


    /**
     * 追加急发运单到急发队列
     *
     * @param eov 订单对象
     * @throws Exception
     */
    @Override
    public void appendQuickOrder(TmsQueueOrderVo eov) throws Exception {
        if (null != eov) {
            TmsQueueApi.removeOrder(eov.getWaybillId(), eov.getTmsSerialNo());
            TmsQueueApi.removeQuickOrder(eov.getWaybillId(), eov.getTmsSerialNo());
            TmsQueueApi.appendQuickOrder(eov);
        }
    }

    /**
     * 查询队列司机信息
     *
     * @param vo 查询条件
     * @param pageVo 分页对象
     * @return
     * @throws Exception
     */
    @Override
    public Map<String, Object> listQueueDriverByCondition(QueueDriverVo vo, PageVo pageVo) throws Exception {
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> paramsMap = new HashMap<>();
        Map<String, Object> countMap = new HashMap<>();
        Integer totalRecord = 0;
        // 获取队列信息
        List<TmsQueueDriverVo> driverVos = TmsQueueApi.driverList();
        if (CollectionUtils.isNotEmpty(driverVos)) {
            List<String> phones = Lists.newArrayList();
            List<String> countPhones = Lists.newArrayList();
            if (StringUtils.isNotBlank(vo.getPhone()) && StringUtils.isBlank(vo.getName())) {
                phones.add(vo.getPhone());
                paramsMap.putIfAbsent("phone", phones);
                countMap.putIfAbsent("phone", phones);
            } else if (StringUtils.isBlank(vo.getName()) && StringUtils.isBlank(vo.getPhone())) {
                int end = pageVo.getPageNo() * pageVo.getPageSize();
                for (int i = pageVo.getStartIndex(); i < end && i < driverVos.size(); i ++) {
                    phones.add(driverVos.get(i).getPhone());
                }
                driverVos.stream().forEach(v -> {
                    countPhones.add(v.getPhone());
                });
                paramsMap.putIfAbsent("phone", phones);
                countMap.putIfAbsent("phone", countPhones);
            } else if (StringUtils.isNotBlank(vo.getPhone()) && StringUtils.isNotBlank(vo.getName())) {
                phones.add(vo.getPhone());
                paramsMap.putIfAbsent("phone", phones);
                countMap.putIfAbsent("phone", phones);
                paramsMap.putIfAbsent("name", vo.getName());
                countMap.putIfAbsent("name", vo.getName());
            } else if (StringUtils.isBlank(vo.getPhone()) && StringUtils.isNotBlank(vo.getName())) {
                paramsMap.putIfAbsent("name", vo.getName());
                countMap.putIfAbsent("name", vo.getName());
            }
        }
        pageVo.setTotalRecord(sUserViewMapper.countQueueDriver(countMap));
        List<QueueDriverVo> queueDriverVos = sUserViewMapper.listQueueDriver(paramsMap);
        if (CollectionUtils.isNotEmpty(queueDriverVos)) {
            for (int i = 0; i < queueDriverVos.size(); i++) {
                QueueDriverVo v = queueDriverVos.get(i);
                for (int k = 0; k < driverVos.size(); k++) {
                    TmsQueueDriverVo vv = driverVos.get(k);
                    if (Objects.equals(v.getPhone(), vv.getPhone())) {
                        v.setQueue(k + 1);
                        v.setQueueTime(DateUtils.transferLongToDate("yyyy-MM-dd HH:mm:ss", vv.getDateTime()));
                        break;
                    }
                }
            }
            Collections.sort(queueDriverVos);
        }
        map.putIfAbsent("page", pageVo);
        map.putIfAbsent("list", queueDriverVos);
        return map;
    }

    @Override
    public List<QueueDriverVo> exportExecl(QueueDriverVo vo) throws Exception {
        Map<String, Object> paramsMap = new HashMap<>();
        // 获取队列信息
        List<TmsQueueDriverVo> driverVos = TmsQueueApi.driverList();
        if (CollectionUtils.isNotEmpty(driverVos)) {
            List<String> phones = Lists.newArrayList();
            if (StringUtils.isNotBlank(vo.getPhone())) {
                phones.add(vo.getPhone());
            } else if (StringUtils.isBlank(vo.getName()) && StringUtils.isBlank(vo.getPhone())) {
                driverVos.stream().forEach(v -> {
                    phones.add(v.getPhone());
                });
            }
            if (CollectionUtils.isNotEmpty(phones)) {
                paramsMap.put("phone", phones);
            }
            if (StringUtils.isNotBlank(vo.getName())) {
                paramsMap.put("name", vo.getName());
            }
        }
        List<QueueDriverVo> queueDriverVos = sUserViewMapper.listQueueDriver(paramsMap);
        if (CollectionUtils.isNotEmpty(queueDriverVos)) {
            queueDriverVos.stream().forEach(v -> {
                driverVos.stream().forEach(vv -> {
                    if (Objects.equals(v.getPhone(), vv.getPhone())) {
                        v.setQueue(Integer.valueOf(vv.getNubmer() + ""));
                        v.setQueueTime(DateUtils.transferLongToDate("yyyy-MM-dd HH:mm:ss", vv.getDateTime()));
                    }
                });
            });
        }
        return queueDriverVos;
    }
}
